<?php
class Pageley_Domain_Attribute_Composite extends Pageley_Domain_Attribute_Basic {

	private $attributes;
	private $className;

	public function __construct($name, $className, $attributes) {
		parent::__construct($name);
		$this->addValidator(new Pageley_Domain_Validator_Composite($this));
		$this->attributes = $attributes;
		$this->className = $className;
	}

	public function validate($value, $propertyName, $target) {
		if($value !== null) {
			$errors = new Pageley_Util_ArrayMap();
			foreach($this->attributes as $subPropertyName => $attribute) {
				try {
					$attribute->validate(
						$value->get($subPropertyName),
						$propertyName . "." . $subPropertyName,
						$target
					);
				} catch(Pageley_Domain_Validator_Exception $e) {
					$errors->putAll($e->getErrors());
				}
			}
			if($errors->size() > 0) {
				throw new Pageley_Domain_Validator_Exception($errors);
			}
		}
	}

    public function getAttribute($propertyName) {
        $subpropertyName = null;
        if(Pageley_Util_String::contains($propertyName, ".")) {
            $subpropertyName = Pageley_Util_String::substringAfter($propertyName, ".");
            $propertyName = Pageley_Util_String::substringBefore($propertyName, ".");
        }
        $attribute = $this->attributes->get($propertyName);
        if($subpropertyName !== null) {
            $attribute = $attribute->getAttribute($subpropertyName);
        }
        if($attribute === null) {
            throw new Pageley_Domain_IllegalAttributeException("No such property: '" . $this->getName() . "." . $propertyName . "'.");
        }
        return $attribute;
    }

    public function getAttributes() {
        return $this->attributes;
    }

    public function isComposite() {
    	return true;
    }

    public function isInstance($value) {
    	$class = new ReflectionClass($this->className);
    	return $class->isInstance($value);
    }

    public function newInstance($properties) {
    	return Pageley_Util_Reflection::invokeStaticMethod($this->className, "valueOf",
    	   array($properties));
    }

}